package serivce

import (
	"golang.org/x/net/websocket"
	"log"
	"sync"
	"time"
)

type Service struct {
	wsConn    *websocket.Conn
	inChan    chan []byte //写入
	outChan   chan []byte //读取
	closeChan chan []byte
	mutex     sync.Mutex //线程锁
	isClose   bool
}

func IniConnection(wsConn *websocket.Conn) (service *Service, err error) {
	service = &Service{
		wsConn:    wsConn,
		inChan:    make(chan []byte, 1000),
		outChan:   make(chan []byte, 1000),
		closeChan: make(chan []byte, 1),
		isClose:   false,
	}
	go service.readLoop()
	go service.writeLoop()
	go func() {
		for {
			//心跳监听
			_ = service.WriteMessage([]byte("EOF"))
			time.Sleep(time.Second * 5)
		}
	}()
	return
}

func (service *Service) ReadMessage() (data []byte, err error) {

	data = <-service.inChan
	return
}
func (service *Service) WriteMessage(data []byte) (err error) {
	service.outChan <- data
	return
}

func (service *Service) Close() {
	_ = service.wsConn.Close()

	service.mutex.Lock()
	if !service.isClose {
		close(service.closeChan) //close 防止channel 堵塞 关闭channel
		service.isClose = true
	}
	service.mutex.Unlock()
}

func (service *Service) readLoop() {
	var (
		data []byte
		err  error
	)
	for {
		if err = websocket.Message.Receive(service.wsConn, &data); err != nil {
			service.Close()
			_ = log.Output(1, "接收数据失败"+err.Error())
			return
		}

		select {
		case service.inChan <- data:
		case <-service.closeChan:
			service.Close()
			//default:
			//	service.Close()
		}
	}

}
func (service *Service) writeLoop() {
	var (
		data []byte
		err  error
	)
	for {
		select {
		case data = <-service.outChan:
		case <-service.closeChan:
			service.Close()
		}

		if err = websocket.Message.Send(service.wsConn, string(data)); err != nil {
			service.Close()
			_ = log.Output(1, "发送数据失败"+err.Error())
			return
		}
	}
}

/**
广播
*/

func (service *Service) Broadcast(clients []*websocket.Conn, data []byte, selfSend bool) {
	var (
		err error
	)

	for _, ws := range clients {
		if ws == service.wsConn && !selfSend {
			continue
		}
		if _, err = ws.Write(data); err != nil {
			service.Close()
			_ = log.Output(1, "广播发送数据失败"+err.Error())
			return
		}
	}
}
